#pragma once

#include <zGraphicsConfig.hpp>
#include "Context.hpp"
#ifdef ZZZ_CONTEXT_MFC
#include <common.hpp>
#include "../Renderer/Renderer.hpp"
#include <Windows.h>

namespace zzz{
class ZGRAPHICS_CLASS SingleViewContext : public Context {
public:
  virtual ~SingleViewContext();

public:
  bool Initialize(HWND hWnd);
  void Redraw() {
    ::InvalidateRect(hWnd_,NULL,TRUE);
  }
  void SwapBuffer() {
    SwapBuffers(hDC_);
  }
  void MakeCurrent() {
    wglMakeCurrent(hDC_,hRC_);
    Context::MakeCurrent();
  }
  void HideCursor() {
    ::ShowCursor(FALSE);
  }
  void ShowCursor() {
    ::ShowCursor(TRUE);
  }
public:
  virtual void OnMouseMove(unsigned int nFlags,int x,int y) {
    if (!own_mouse_ && gui_ && gui_->OnMouseMove(nFlags,x,y)) return;
    return renderer_->OnMouseMove(nFlags,x,y);
  }
  virtual void OnLButtonDown(unsigned int nFlags,int x,int y) {
    if (!own_mouse_ && gui_ && gui_->OnLButtonDown(nFlags,x,y)) return;
    return renderer_->OnLButtonDown(nFlags,x,y);
  }
  virtual void OnLButtonUp(unsigned int nFlags,int x,int y) {
    if (!own_mouse_ && gui_ && gui_->OnLButtonUp(nFlags,x,y)) return;
    return renderer_->OnLButtonUp(nFlags,x,y);
  }
  virtual void OnRButtonDown(unsigned int nFlags,int x,int y) {
    if (!own_mouse_ && gui_ && gui_->OnRButtonDown(nFlags,x,y)) return;
    return renderer_->OnRButtonDown(nFlags,x,y);
  }
  virtual void OnRButtonUp(unsigned int nFlags,int x,int y) {
    if (!own_mouse_ && gui_ && gui_->OnLButtonUp(nFlags,x,y)) return;
    return renderer_->OnRButtonUp(nFlags,x,y);
  }
  virtual void OnMButtonDown(unsigned int nFlags,int x,int y) {
    if (!own_mouse_ && gui_ && gui_->OnMButtonDown(nFlags,x,y)) return;
    return renderer_->OnMButtonDown(nFlags,x,y);
  }
  virtual void OnMButtonUp(unsigned int nFlags,int x,int y) {
    if (!own_mouse_ && gui_ && gui_->OnMButtonDown(nFlags,x,y)) return;
    return renderer_->OnMButtonUp(nFlags,x,y);
  }
  virtual void OnMouseWheel(unsigned int nFlags, int zDelta, int x,int y) {
    if (!own_mouse_ && gui_ && gui_->OnMouseWheel(nFlags,zDelta,x,y)) return;
    return renderer_->OnMouseWheel(nFlags,zDelta,x,y);
  }
  virtual void OnSize(unsigned int nType, int cx, int cy) {
    renderer_->OnSize(nType,cx,cy);
    if (gui_) gui_->OnSize(nType,cx,cy);
    width_=cx;height_=cy;
  }
  virtual void OnChar(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
    MFC2ZZZ(nChar,nFlags);
    if (!own_keyboard_ && gui_ && gui_->OnChar(nChar,nRepCnt,nFlags)) return;
    return renderer_->OnChar(nChar,nRepCnt,nFlags);
  }
  virtual void OnKeyDown(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
    MFC2ZZZ(nChar,nFlags);
    if (!own_keyboard_ && gui_ && gui_->OnKeyDown(nChar,nRepCnt,nFlags)) return;
    return renderer_->OnKeyDown(nChar,nRepCnt,nFlags);
  }
  virtual void OnKeyUp(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
    MFC2ZZZ(nChar,nFlags);
    if (!own_keyboard_ && gui_ && gui_->OnKeyUp(nChar,nRepCnt,nFlags)) return;
    return renderer_->OnKeyUp(nChar,nRepCnt,nFlags);
  }
protected:
  HDC hDC_;
  HGLRC hRC_;
  bool GLinited_,GLEWinited_;
  GLint DefaultDrawBuffer_;
  HWND hWnd_;

private:
  bool InitGL();
  int InitMultisample();
  bool SetupPixelFormat(int pf=0);

};


//1 Define a renderer class
//2 put renderer_.RenderScene() in OnDraw()
//3 Put the following macro in the correct file
#define PUT_IN_VIEW_H  public:\
            zzz::SingleViewContext zzzContext_; \
            afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); \
            afx_msg void OnMouseMove(UINT nFlags, CPoint point); \
            afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); \
            afx_msg void OnMButtonDown(UINT nFlags, CPoint point); \
            afx_msg void OnMButtonUp(UINT nFlags, CPoint point); \
            afx_msg void OnLButtonDown(UINT nFlags, CPoint point); \
            afx_msg void OnLButtonUp(UINT nFlags, CPoint point); \
            afx_msg void OnRButtonDown(UINT nFlags, CPoint point); \
            afx_msg void OnRButtonUp(UINT nFlags, CPoint point); \
            afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); \
            afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); \
            afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags); \
            afx_msg void OnSize(UINT nType, int cx, int cy); \
            afx_msg BOOL OnEraseBkgnd(CDC* pDC); \
            afx_msg void OnPaint();


#define PUT_IN_VIEW_CPP_MESSAGE_MAP    ON_WM_CREATE()\
                    ON_WM_MOUSEMOVE()\
                    ON_WM_MOUSEWHEEL()\
                    ON_WM_MBUTTONDOWN()\
                    ON_WM_MBUTTONUP()\
                    ON_WM_LBUTTONDOWN()\
                    ON_WM_LBUTTONUP()\
                    ON_WM_RBUTTONDOWN()\
                    ON_WM_RBUTTONUP()\
                    ON_WM_CHAR()\
                    ON_WM_KEYDOWN()\
                    ON_WM_KEYUP()\
                    ON_WM_SIZE()\
                    ON_WM_ERASEBKGND()\
                    ON_WM_PAINT()



#define PUT_IN_VIEW_CPP(viewclass,varrenderer) \
int viewclass::OnCreate(LPCREATESTRUCT lpCreateStruct){if (CView::OnCreate(lpCreateStruct) == -1) return -1;zzzContext_.SetRenderer(&varrenderer);zzzContext_.Initialize(GetSafeHwnd());return 0;}\
void viewclass::OnMouseMove(UINT nFlags, CPoint point){zzzContext_.OnMouseMove(nFlags,point.x,point.y);CView::OnMouseMove(nFlags, point);}\
BOOL viewclass::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt){zzzContext_.OnMouseWheel(nFlags,zDelta/120,pt.x,pt.y);return CView::OnMouseWheel(nFlags, zDelta, pt);}\
void viewclass::OnMButtonDown(UINT nFlags, CPoint point){SetFocus();SetCapture();zzzContext_.OnMButtonDown(nFlags,point.x,point.y);CView::OnMButtonDown(nFlags, point);}\
void viewclass::OnMButtonUp(UINT nFlags, CPoint point){zzzContext_.OnMButtonUp(nFlags,point.x,point.y);CView::OnMButtonUp(nFlags, point);ReleaseCapture();}\
void viewclass::OnLButtonDown(UINT nFlags, CPoint point){SetFocus();SetCapture();zzzContext_.OnLButtonDown(nFlags,point.x,point.y);CView::OnLButtonDown(nFlags, point);}\
void viewclass::OnLButtonUp(UINT nFlags, CPoint point){zzzContext_.OnLButtonUp(nFlags,point.x,point.y);CView::OnLButtonUp(nFlags, point);ReleaseCapture();}\
void viewclass::OnRButtonDown(UINT nFlags, CPoint point){SetFocus();SetCapture();zzzContext_.OnRButtonDown(nFlags,point.x,point.y);CView::OnRButtonDown(nFlags, point);}\
void viewclass::OnRButtonUp(UINT nFlags, CPoint point){zzzContext_.OnRButtonUp(nFlags,point.x,point.y);CView::OnRButtonUp(nFlags, point);ReleaseCapture();}\
void viewclass::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags){zzzContext_.OnChar(nChar,nRepCnt,nFlags);CView::OnChar(nChar, nRepCnt, nFlags);}\
void viewclass::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags){zzzContext_.OnKeyDown(nChar,nRepCnt,nFlags);CView::OnKeyDown(nChar, nRepCnt, nFlags);}\
void viewclass::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags){zzzContext_.OnKeyUp(nChar,nRepCnt,nFlags);CView::OnKeyUp(nChar, nRepCnt, nFlags);}\
void viewclass::OnSize(UINT nType, int cx, int cy){CView::OnSize(nType, cx, cy);zzzContext_.OnSize(nType,cx,cy);}\
BOOL viewclass::OnEraseBkgnd(CDC* pDC){return TRUE;}\
void viewclass::OnPaint(){CPaintDC dc(this);zzzContext_.RenderScene();OnDraw(&dc);}

#define PUT_IN_VIEW_CPP_GUI(viewclass,varrenderer,vargui) \
int viewclass::OnCreate(LPCREATESTRUCT lpCreateStruct){if (CView::OnCreate(lpCreateStruct) == -1) return -1;zzzContext_.SetRenderer(&varrenderer);zzzContext_.SetGraphicsGUI(&vargui);zzzContext_.Initialize(GetSafeHwnd());return 0;}\
void viewclass::OnMouseMove(UINT nFlags, CPoint point){zzzContext_.OnMouseMove(nFlags,point.x,point.y);CView::OnMouseMove(nFlags, point);}\
BOOL viewclass::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt){zzzContext_.OnMouseWheel(nFlags,zDelta/120,pt.x,pt.y);return CView::OnMouseWheel(nFlags, zDelta, pt);}\
void viewclass::OnMButtonDown(UINT nFlags, CPoint point){SetFocus();SetCapture();zzzContext_.OnMButtonDown(nFlags,point.x,point.y);CView::OnMButtonDown(nFlags, point);}\
void viewclass::OnMButtonUp(UINT nFlags, CPoint point){zzzContext_.OnMButtonUp(nFlags,point.x,point.y);CView::OnMButtonUp(nFlags, point);ReleaseCapture();}\
void viewclass::OnLButtonDown(UINT nFlags, CPoint point){SetFocus();SetCapture();zzzContext_.OnLButtonDown(nFlags,point.x,point.y);CView::OnLButtonDown(nFlags, point);}\
void viewclass::OnLButtonUp(UINT nFlags, CPoint point){zzzContext_.OnLButtonUp(nFlags,point.x,point.y);CView::OnLButtonUp(nFlags, point);ReleaseCapture();}\
void viewclass::OnRButtonDown(UINT nFlags, CPoint point){SetFocus();SetCapture();zzzContext_.OnRButtonDown(nFlags,point.x,point.y);CView::OnRButtonDown(nFlags, point);}\
void viewclass::OnRButtonUp(UINT nFlags, CPoint point){zzzContext_.OnRButtonUp(nFlags,point.x,point.y);CView::OnRButtonUp(nFlags, point);ReleaseCapture();}\
void viewclass::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags){zzzContext_.OnChar(nChar,nRepCnt,nFlags);CView::OnChar(nChar, nRepCnt, nFlags);}\
void viewclass::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags){zzzContext_.OnKeyDown(nChar,nRepCnt,nFlags);CView::OnKeyDown(nChar, nRepCnt, nFlags);}\
void viewclass::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags){zzzContext_.OnKeyUp(nChar,nRepCnt,nFlags);CView::OnKeyUp(nChar, nRepCnt, nFlags);}\
void viewclass::OnSize(UINT nType, int cx, int cy){CView::OnSize(nType, cx, cy);zzzContext_.OnSize(nType,cx,cy);}\
BOOL viewclass::OnEraseBkgnd(CDC* pDC){return TRUE;}\
void viewclass::OnPaint(){CPaintDC dc(this);zzzContext_.RenderScene();OnDraw(&dc);}

}

#endif